﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Chloe.MySql;
using Chloe.SQLite;
using Chloe.SqlServer;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using ICSharpCode.AvalonEdit;
using Kang.DbDoc.DatabaseHelper;
using Kang.DbDoc.Domains;
using Kang.DbDoc.Enums;
using Kang.DbDoc.Interfaces;
using Kang.DbDoc.Models;
using Kang.DbDoc.ServicesImpl;
using Kang.DbDoc.Views;
using Kang.ExtendMethod;
using Kang.ExtendMethod.Log;
using MahApps.Metro.Controls.Dialogs;
using Microsoft.Win32;
using static Org.BouncyCastle.Math.EC.ECCurve;

namespace Kang.DbDoc.ViewModels
{
    public class MainWindowViewModel : ObservableRecipient
    {
        readonly Logger logger = LogManager.GetCurrentClassLogger();

        IExport chmService = new ChmExportService();
        IExport wordService = new WordExportService();
        IExport pdfService = new PdfExportService();
        IExport excelService = new ExcelExportService();
        IExport markdownService = new MarkdownExportService();
        IExport htmlService = new HtmlExportService();

        private TextEditor _editor;
        public TextEditor Editor
        {
            get
            {
                return _editor;
            }
            set
            {
                _editor = value;
            }
        }

        private string _title = "";
        public string Title
        {
            get
            {
                return _title;
            }
            set
            {
                SetProperty(ref _title, value);
            }
        }

        private string _name = "DbDoc";
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                SetProperty(ref _name, value);
            }
        }

        private string _version = "1.0.0.1";
        public string Version
        {
            get
            {
                return _version;
            }
            set
            {
                SetProperty(ref _version, value);
            }
        }

        private string _nameLabel = "表：";
        public string NameLabel
        {
            get
            {
                return _nameLabel;
            }
            set
            {
                SetProperty(ref _nameLabel, value);
            }
        }

        private bool _isLoading = false;
        public bool IsLoading
        {
            get
            {
                return _isLoading;
            }
            set
            {
                SetProperty(ref _isLoading, value);
            }
        }

        private bool _isRoutine = false;
        public bool IsRoutine
        {
            get
            {
                return _isRoutine;
            }
            set
            {
                SetProperty(ref _isRoutine, value);
            }
        }

        private bool _isTableOrView = false;
        public bool IsTableOrView
        {
            get
            {
                return _isTableOrView;
            }
            set
            {
                SetProperty(ref _isTableOrView, value);
            }
        }

        private Visibility _showLastDatabase = Visibility.Collapsed;
        public Visibility ShowLastDatabase
        {
            get
            {
                return _showLastDatabase;
            }
            set
            {
                SetProperty(ref _showLastDatabase, value);
            }
        }

        public string SearchWord { get; set; } = string.Empty;

        public string Status { get; set; } = string.Empty;

        public string LastDatabaseName { get; set; } = string.Empty;

        private DatabaseModel _database = null;
        public DatabaseModel Database
        {
            get
            {
                return _database;
            }
            set
            {
                SetProperty(ref _database, value);
            }
        }

        public MainWindowViewModel()
        {
            Version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
            Title = $"{Name}    By:Zekang Hao";
            Status = "完成";
            if (App.Config != null)
            {
                if (App.Config.LastOpenDatabase.HasValue)
                {
                    using (var my = App.sqlite)
                    {
                        var name = my.Query<DbServer>().Where(x => x.Id == App.Config.LastOpenDatabase).Select(x => x.Name).FirstOrDefault();
                        if (name.IsNotBlank())
                        {
                            ShowLastDatabase = Visibility.Visible;
                            LastDatabaseName = name;
                        }
                        else
                        {
                            ShowLastDatabase = Visibility.Collapsed;
                        }
                    }
                }
            }
        }

        public ICommand About
        {
            get
            {
                return new RelayCommand(() =>
                {
                    App.ShowMessageAsync("关于", $"作者：Zekang Hao{Environment.NewLine}邮箱：admin@haozekang.com{Environment.NewLine}作品界面参考DBCHM项目：https://gitee.com/dotnetchina/DBCHM"
                        , MessageDialogStyle.Affirmative
                        , new MetroDialogSettings()
                        {
                            AffirmativeButtonText = "确认"
                        });
                });
            }
        }

        public ICommand TableOrViewOrRoutineChanged
        {
            get
            {
                return new RelayCommand<object>((item) =>
                {
                    TableOrViewModel tableOrView = null;
                    RoutineModel routine = null;
                    switch (item.GetType().Name)
                    {
                        case "TableOrViewModel":
                            IsRoutine = false;
                            IsTableOrView = true;
                            tableOrView = item as TableOrViewModel;
                            if (tableOrView == null)
                            {
                                return;
                            }
                            if (tableOrView.Type == TableTypeEnum.Table)
                            {
                                NameLabel = "表：";
                            }
                            else
                            {
                                NameLabel = "视图：";
                            }
                            break;
                        case "RoutineModel":
                            IsRoutine = true;
                            IsTableOrView = false;
                            routine = item as RoutineModel;
                            if (routine == null)
                            {
                                return;
                            }
                            if (routine.Type == RoutineTypeEnum.Function)
                            {
                                NameLabel = "方法：";
                            }
                            else
                            {
                                NameLabel = "存储过程：";
                            }
                            if (Editor != null)
                            {
                            }
                            break;
                    }
                });
            }
        }

        public ICommand ShowDatabaseManager
        {
            get
            {
                return new RelayCommand(async () =>
                {
                    DatabaseManagerPage page = new DatabaseManagerPage()
                    {
                        ShowCloseButton = true,
                        ChildWindowHeight = 500,
                        ChildWindowWidth = 1000,
                        IsModal = true,
                        OverlayBrush = new SolidColorBrush { Opacity = 0.5, Color = Colors.Black },
                    };
                    var database = await App.ShowChildWindowAsync<DatabaseModel>(page);
                    if (database == null)
                    {
                        return;
                    }
                    try
                    {
                        Database = database;
                        LoadDatabaseData(Database);
                    }
                    catch (Exception e)
                    {
                        App.ShowMessageAsync("错误", e.Message);
                    }
                });
            }
        }

        public ICommand RefreshLastDatabase
        {
            get
            {
                return new RelayCommand(async () =>
                {
                    if (App.Config == null)
                    {
                        return;
                    }
                    if (!App.Config.LastOpenDatabase.HasValue)
                    {
                        return;
                    }
                    var id = App.Config.LastOpenDatabase.Value;
                    using (var my = App.sqlite)
                    {
                        Database = my.Query<DbServer>().Where(x => x.Id == id).Select(x => new DatabaseModel(x.DbType)
                        {
                            Id = x.Id,
                            Name = x.Name,
                            DatabaseHost = x.DatabaseHost,
                            DatabasePort = x.DatabasePort ?? 0,
                            DatabaseName = x.DatabaseName,
                            DatabaseUsername = x.DatabaseUsername,
                            DatabasePassword = x.DatabasePassword,
                            TimeOut = x.TimeOut ?? 0,
                            IsSslMode = x.IsSslMode ?? false,
                            ConnectionString = x.ConnectionString,
                            Remark = x.Remark,
                        }).FirstOrDefault();
                    }
                    Refresh.Execute(null);
                });
            }
        }

        public ICommand Refresh
        {
            get
            {
                return new RelayCommand(() =>
                {
                    if (Database == null)
                    {
                        App.ShowMessageAsync("提醒", "请先连接数据库！");
                        return;
                    }
                    try
                    {
                        ShowLastDatabase = Visibility.Collapsed;
                        Database.Tables.Clear();
                        Database.Views.Clear();
                        Database.Functions.Clear();
                        Database.Procedures.Clear();
                        LoadDatabaseData(Database);
                    }
                    catch (Exception e)
                    {
                        App.ShowMessageAsync("错误", e.Message);
                    }
                });
            }
        }

        public ICommand ExportForChm
        {
            get
            {
                return new RelayCommand(() =>
                {
                    Task.Run(() =>
                    {
                        Export(chmService, ShowExportFilepathDialog("CHM", "chm"), Database);
                    });
                });
            }
        }

        public ICommand ExportForWord
        {
            get
            {
                return new RelayCommand(() =>
                {
                    Task.Run(() =>
                    {
                        Export(wordService, ShowExportFilepathDialog("Word", "docx"), Database);
                    });
                });
            }
        }

        public ICommand ExportForExcel
        {
            get
            {
                return new RelayCommand(() =>
                {
                    Task.Run(() =>
                    {
                        Export(excelService, ShowExportFilepathDialog("Excel", "xlsx"), Database);
                    });
                });
            }
        }

        public ICommand ExportForPdf
        {
            get
            {
                return new RelayCommand(() =>
                {
                    Task.Run(() =>
                    {
                        Export(pdfService, ShowExportFilepathDialog("PDF", "pdf"), Database);
                    });
                });
            }
        }

        public ICommand ExportForHtml
        {
            get
            {
                return new RelayCommand(() =>
                {
                    Task.Run(() =>
                    {
                        Export(htmlService, ShowExportFilepathDialog("HTML", "html"), Database);
                    });
                });
            }
        }

        public ICommand ExportForMarkdown
        {
            get
            {
                return new RelayCommand(() =>
                {
                    Task.Run(() =>
                    {
                        Export(markdownService, ShowExportFilepathDialog("Markdown", "md"), Database);
                    });
                });
            }
        }

        public ICommand CheckAll
        {
            get
            {
                return new RelayCommand<string>((t) =>
                {
                    if (Database == null)
                    {
                        return;
                    }

                    switch (t)
                    {
                        case "0":
                            if (Database.Tables != null)
                            {
                                Database.Tables.ForEach(x => x.IsCheck = true);
                            }
                            if (Database.Views != null)
                            {
                                Database.Views.ForEach(x => x.IsCheck = true);
                            }
                            if (Database.Functions != null)
                            {
                                Database.Functions.ForEach(x => x.IsCheck = true);
                            }
                            if (Database.Procedures != null)
                            {
                                Database.Procedures.ForEach(x => x.IsCheck = true);
                            }
                            break;
                        case "1":
                            if (Database.Tables != null)
                            {
                                Database.Tables.ForEach(x => x.IsCheck = true);
                            }
                            break;
                        case "2":
                            if (Database.Views != null)
                            {
                                Database.Views.ForEach(x => x.IsCheck = true);
                            }
                            break;
                        case "3":
                            if (Database.Functions != null)
                            {
                                Database.Functions.ForEach(x => x.IsCheck = true);
                            }
                            break;
                        case "4":
                            if (Database.Procedures != null)
                            {
                                Database.Procedures.ForEach(x => x.IsCheck = true);
                            }
                            break;
                    }
                });
            }
        }

        public ICommand UncheckAll
        {
            get
            {
                return new RelayCommand<string>((t) =>
                {
                    if (Database == null)
                    {
                        return;
                    }

                    switch (t)
                    {
                        case "0":
                            if (Database.Tables != null)
                            {
                                Database.Tables.ForEach(x => x.IsCheck = false);
                            }
                            if (Database.Views != null)
                            {
                                Database.Views.ForEach(x => x.IsCheck = false);
                            }
                            if (Database.Functions != null)
                            {
                                Database.Functions.ForEach(x => x.IsCheck = false);
                            }
                            if (Database.Procedures != null)
                            {
                                Database.Procedures.ForEach(x => x.IsCheck = false);
                            }
                            break;
                        case "1":
                            if (Database.Tables != null)
                            {
                                Database.Tables.ForEach(x => x.IsCheck = false);
                            }
                            break;
                        case "2":
                            if (Database.Views != null)
                            {
                                Database.Views.ForEach(x => x.IsCheck = false);
                            }
                            break;
                        case "3":
                            if (Database.Functions != null)
                            {
                                Database.Functions.ForEach(x => x.IsCheck = false);
                            }
                            break;
                        case "4":
                            if (Database.Procedures != null)
                            {
                                Database.Procedures.ForEach(x => x.IsCheck = false);
                            }
                            break;
                    }
                });
            }
        }

        public string ShowExportFilepathDialog(string type, string ext)
        {
            if (Database == null)
            {
                App.ShowMessageAsync("提醒", "请先连接数据库！");
                return string.Empty;
            }
            string name = string.Empty;
            if (Database.DatabaseType == DatabaseTypeEnum.SQLite)
            {
                name = Path.GetFileName(Database.DatabaseName);
            }
            else
            {
                name = Database.DatabaseName;
            }
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Title = $"{name}表结构导出为{type}";
            saveFileDialog.DefaultExt = $".{ext}";
            saveFileDialog.Filter = $"{type}文件|*.{ext}";
            saveFileDialog.FileName = $"{name}-表结构文档.{ext}";
            var flag = saveFileDialog.ShowDialog();
            App.Current.Dispatcher.Invoke(() =>
            {
                App.Current.MainWindow.Focus();
            });
            if (flag != true)
            {
                return string.Empty;
            }
            return saveFileDialog.FileName;
        }

        public void LoadDatabaseData(DatabaseModel database)
        {
            if (database == null)
            {
                App.ShowMessageAsync("提醒", "请先连接数据库！");
                return;
            }
            var connectionStringLower = database.ConnectionString.ToLower();
            App.Current.Dispatcher.Invoke(() =>
            {
                Title = $"{Name}    目前连接：{database.Name}({database.DatabaseType})    By:Zekang Hao";
                IsLoading = true;
            });
            Task.Run(() =>
            {
                try
                {
                    database.Load(SearchWord);
                    App.Current.Dispatcher.Invoke(() =>
                    {
                        IsLoading = false;
                    });
                }
                catch (Exception e)
                {
                    App.Current.Dispatcher.Invoke(() =>
                    {
                        App.ShowMessageAsync("错误", e.Message);
                    });
                }
                finally
                {
                    App.Current.Dispatcher.Invoke(() =>
                    {
                        IsLoading = false;
                    });
                }
            });
            App.Current.Dispatcher.Invoke(() =>
            {
                App.Config.LastOpenDatabase = database.Id;
            });
        }

        private void Export(IExport service, string filename, DatabaseModel database)
        {
            if (database == null || filename.IsBlank())
            {
                return;
            }
            App.Current.Dispatcher.Invoke(() =>
            {
                IsLoading = true;
                Status = $"正在导出文档至：{filename}";
            });
            string error = string.Empty;
            bool exportFlag = false;
            if (Database.Tables.IsBlank() && Database.Views.IsBlank() && Database.Functions.IsBlank() && Database.Procedures.IsBlank())
            {
                exportFlag = service.Export(filename,
                    database,
                    database.Tables.ToList(),
                    database.Views.ToList(),
                    database.Functions.ToList(),
                    database.Procedures.ToList(),
                    ref error);
            }
            else
            {
                exportFlag = service.Export(filename,
                    database,
                    database.Tables.Where(x => x.IsCheck == true).ToList(),
                    database.Views.Where(x => x.IsCheck == true).ToList(),
                    database.Functions.Where(x => x.IsCheck == true).ToList(),
                    database.Procedures.Where(x => x.IsCheck == true).ToList(),
                    ref error);
            }
            App.Current.Dispatcher.Invoke(() =>
            {
                IsLoading = false;
                Status = "完成";
            });
            if (exportFlag)
            {
                App.ShowMessageAsync("信息", $"导出成功！{Environment.NewLine}文件路径为：{filename}");
                Process.Start(filename);
            }
            else
            {
                logger.Error(error);
                App.ShowMessageAsync("错误", error);
            }
        }
    }
}
